package com.mmall.concurrency.example.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class CyclicBarrierExample1 {
    /**
     * 字面意思回环栅栏，通过它可以实现让一组线程等待至某个状态之后再全部同时执行。
     * 叫做回环是因为当所有等待线程都被释放以后，CyclicBarrier可以被重用。
     * 我们暂且把这个状态就叫做barrier，当调用await()方法之后，线程就处于barrier了。
     */

    /**
     * 参数parties指让多少个线程或者任务等待至barrier状态；
     * 参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
     */

    /**
     * 使用场景：
     * 例如一个业务，需要5个线程将数据都拿取到了再开始处理他们
     * 线程1拿数据
     * 线程2拿数据
     * 线程3拿数据
     * 线程4拿数据
     * 线程5拿数据
     * 线程1、2、3、4、5同时被释放开始处理刚刚拿到的数据
     */
    private static CyclicBarrier barrier = new CyclicBarrier(5);

    public static void main(String[] args) throws Exception {

        ExecutorService executor = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int threadNum = i;
            Thread.sleep(1000);
            executor.execute(() -> {
                try {
                    race(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                }
            });
        }
        executor.shutdown();
    }

    private static void race(int threadNum) throws Exception {
        Thread.sleep(1000);
        log.info("{} is ready", threadNum);
        // 用来挂起当前线程，直至所有线程都到达barrier状态再同时执行后续任务；
        barrier.await();
        // 例如在这里parties = 5，当有5个线程被挂起，就开始释放这5个，这5个线程会执行下面这一句
        log.info("{} continue", threadNum);
    }
}
